package com.github.bobjoy.java.spi.plugin;

import java.io.File;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 插件类加载器，在插件目录中搜索jar包，
 * 并为发现的资源(jar)构造一个类加载器,将对应的jar添加到classpath中
 */
public class PluginClassLoader extends URLClassLoader {

    private List<JarURLConnection> cachedJarFiles = new ArrayList<>();

    public PluginClassLoader() {
        super(new URL[]{}, findParentClassLoader());
    }

    /**
     * 定位基于当前上下文的父类加载器
     */
    private static ClassLoader findParentClassLoader() {
        ClassLoader parent = PluginClassLoader.class.getClassLoader();
        if (parent == null) {
            parent = PluginClassLoader.class.getClassLoader();
        }
        if (parent == null) {
            parent = ClassLoader.getSystemClassLoader();
        }
        return parent;
    }

    /**
     * 将指定的文件url添加到类加载器的classpath中去，并缓存jar connection，方便以后卸载jar
     */
    public void addURLFile(URL file) {
        try {
            // 打开并缓存文件url连接
            URLConnection uc = file.openConnection();
            if (uc instanceof JarURLConnection) {
                uc.setUseCaches(true);
                ((JarURLConnection) uc).getManifest();
                cachedJarFiles.add((JarURLConnection) uc);
            }
        } catch (Exception e) {
            System.err.println("Failed to cache plugin JAR file: " + file.toExternalForm());
        }
        System.err.println("Load plugin JAR file " + file.toExternalForm());
        addURL(file);
    }

    /**
     * 卸载jar包
     */
    public void unloadJarFiles() {
        Iterator<JarURLConnection> it = cachedJarFiles.iterator();
        while (it.hasNext()) {
            try {
                JarURLConnection url = it.next();
                System.err.println("Unloading plugin JAR file " + url.getJarFile().getName());
                url.getJarFile().close();
                url = null;
            } catch (Exception e) {
                System.err.println("Failed to unload JAR file\n" + e);
            }
            it.remove();
        }
    }

    public static void main(String[] args) throws Exception {
        PluginClassLoader loader = new PluginClassLoader();
        URL url = new File("E:\\workspaces\\study\\java-learning\\spi\\AuthPlugin.jar").toURI().toURL();

        String jarUrl = "jar:" + url.toExternalForm() + "!/";
        loader.addURLFile(new URL(jarUrl));

        Plugin plugin = (Plugin) loader.loadClass("com.bfl.plugin.impl.AuthPlugin").newInstance();
        String str = plugin.sayHello();
        System.out.println(str);

        loader.unloadJarFiles();
        Thread.sleep(3000);

        plugin = (Plugin) loader.loadClass("com.bfl.plugin.impl.AuthPlugin").newInstance();
        str = plugin.sayHello();
        System.out.println(str);
    }
}
